/*********************
* Author:Dzlua
* QQ:505544956
* time:2016/08/08
*/
#include "Control.h"
#include "../edui.h"

EDUI_NAMESPACE_BEGIN

#ifdef EDUI_TEST_NEW_DELETE
int Control::m_newdeleteNum = 0;
int Control::_GetNewDeleteNum()
{
    return m_newdeleteNum;
}
#endif

Control::Control() : m_bFloat(false), m_bVisible(true), m_bEnabled(true), m_bMouseEnabled(true), m_bKeyboardEnabled(false), m_bDragWnd(true),
                    m_parent(0), m_wnd(0), m_cursor(0), m_tabID(0), m_ainmation(0)
{
    m_name.Empty();
}

Control::~Control()
{
    this->SetAnimation(0);
}

Control* Control::GetInterface()
{
    Control* ctrl = new Control;
#ifdef EDUI_TEST_NEW_DELETE
    ++m_newdeleteNum;
    Log("[Control] new control : %d", ctrl);
#endif
#ifdef EDUI_USE_LUAPLUS
    LuaMgrPtr->Add("Control", ctrl);
#endif
    return ctrl;
}

void Control::Release()
{
#ifdef EDUI_TEST_NEW_DELETE
    --m_newdeleteNum;
    Log("[Control] delete control : %s, %d", this->GetName(), this);
#endif
#ifdef EDUI_USE_LUAPLUS
    LuaMgrPtr->Remove(this);
#endif
    delete this;
}


bool Control::IsDragWindow() const
{
    return m_bDragWnd;
}

bool Control::IsInRect(int x, int y)
{
    return m_rc.IsInRect(x, y);
}

bool Control::IsOK() const
{
    //if (m_name.IsEmpty()) return false;
    if (!m_wnd) return false;
    return true;
}

//control name
const char* Control::GetName() const
{
    return m_name.GetString();
}

bool Control::SetName(const char* name)
{
    if (!name) return false;
    m_name = name;
    return true;
}

// render position
Point Control::GetPos() const
{
    return Point(m_rc.x, m_rc.y);
}

bool Control::SetPos(const Point* pt)
{
    if (!pt) return false;
    Rect rc(pt->x, pt->y, m_rc.w, m_rc.h);
    return this->SetRect(&rc);
}

Size Control::GetSize() const
{
    return Size(m_rc.w, m_rc.h);
}

bool Control::SetSize(const Size* sz)
{
    if (!sz) return false;
    Rect rc(m_rc.x, m_rc.y, sz->w, sz->h);
    return this->SetRect(&rc);
}

bool Control::SetRect(const Rect *rc)
{
    if (!rc) return false;
    m_rc = *rc;
    return true;
}

Rect Control::GetRect() const
{
    return m_rc;
}

// real position
Point Control::GetFixedPos() const
{
    return Point(m_rcFixed.x, m_rcFixed.y);
}

bool Control::SetFixedPos(const Point* pt)
{
    if (!pt) return false;
    m_rcFixed.x = pt->x;
    m_rcFixed.y = pt->y;
    return true;
}

Size Control::GetFixedSize() const
{
    return Size(m_rcFixed.w, m_rcFixed.h);
}

bool Control::SetFixedSize(const Size* sz)
{
    if (!sz) return false;
    m_rcFixed.w = sz->w;
    m_rcFixed.h = sz->h;
    return true;
}

bool Control::SetFixedRect(const Rect *rc)
{
    if (!rc) return false;
    m_rcFixed = *rc;
    return true;
}

Rect Control::GetFixedRect() const
{
    return m_rcFixed;
}

Rect1 Control::GetPadding() const
{
    return m_rcPadding;
}

bool Control::SetPadding(const Rect1* padding)
{
    if (!padding) return false;
    m_rcPadding = *padding;
    return true;
}

//user attribute
void* Control::GetUserData() const
{
    Log("[EDUI] Control : unable to use.");
    return 0;
}

void* Control::SetUserData(void* data)
{
    Log("[EDUI] Control : unable to use.");
    return 0;    
}

//
bool Control::IsFloat() const
{
    return m_bFloat;
}

void Control::SetFloat(bool bFloat)
{
    m_bFloat = bFloat;
}

bool Control::IsVisible() const
{
    return m_bVisible;
}

void Control::SetVisible(bool bVisible)
{
    m_bVisible = bVisible;
}

bool Control::IsEnabled() const
{
    return m_bEnabled;
}

void Control::SetEnabled(bool bEnable)
{
    m_bEnabled = bEnable;
}

bool Control::IsMouseEnabled() const
{
    return m_bMouseEnabled;
}

void Control::SetMouseEnabled(bool bEnable)
{
    m_bMouseEnabled = bEnable;
}

bool Control::IsKeyboardEnabled() const
{
    return m_bKeyboardEnabled;
}

void Control::SetKeyboardEnabled(bool bEnable)
{
    m_bKeyboardEnabled = bEnable;
}

bool Control::IsFocused() const
{
    if (m_wnd->GetFocusCtrl() != this) return false;
    return false;
}

void Control::SetFocus()
{
    m_wnd->SetFocusCtrl(this);
}

void Control::KillFocus()
{
    m_wnd->SetFocusCtrl(0);
}

void Control::SetCursor(ICursor* cursor)
{
    m_cursor = cursor;
}

ICursor* Control::GetCursor()
{
    return m_cursor;
}

Color* Control::GetDestColor(const char* value)
{
    if (0 == strcmp(value, "bk")){
        return &m_bkColor;
    }
    return 0;
}

ImageData* Control::GetDestImageData(const char* value)
{
    if (0 == strcmp(value, "bk")){
        return &m_bkImage;
    } else if (0 == strcmp(value, "fore")){
        return &m_foreImage;
    }
    return 0;
}

const Color* Control::GetColor(const char* dstname)
{
    return this->GetDestColor(dstname);
}

typedef std::vector<Color*> VColor;
typedef std::vector<VColor> DestColor;

void Control::SetColor(const char* colorstr)
{
    if (!colorstr) return;

    DestColor destcolor;
    String colorval;

    Parser par(colorstr);
    for (Parser::Attribute* it = par.First(); it; it = par.Next()){
        if (0 == strcmp(it->Name(), "dst")){
            Parser::Value parValue1(it->Value());
            for (const char* value1 = parValue1.First(); value1; value1 = parValue1.Next()){
                VColor vcolor;
                Parser::Value parValue2(value1);
                for (const char* value2 = parValue2.First(); value2; value2 = parValue2.Next()){
                    Color* c = this->GetDestColor(value2);
                    if (c) vcolor.push_back(c);
                }
                if (vcolor.size() > 0){
                    destcolor.push_back(vcolor);
                }
            }
        } else if (0 == strcmp(it->Name(), "color")){
            colorval = it->Value();
        }
    }

    size_t size = destcolor.size();
    size_t i = 0;
    Parser::Value parValue(colorval.GetString());
    for (const char* value = parValue.First(); value; value = parValue.Next()){
        if (i >= size) break;

        Color c = ParserColor(value);
        VColor vcolor = destcolor.at(i);

        for (VColor::iterator it = vcolor.begin(); it != vcolor.end(); ++it){
            if(*it){
                *(*it) = c;
            }
        }

        ++i;
    }

    this->Invaldate();
}

const ImageData* Control::GetImage(const char* dstname)
{
    return this->GetDestImageData(dstname);
}

typedef std::vector<ImageData*> VImageData;
typedef std::vector<VImageData> DestImageData;

void Control::SetImage(const char* imagestr)
{
    if (!imagestr) return;

    DestImageData destimagedata;
    String imagevalue;

    Parser par(imagestr);
    for (Parser::Attribute* it = par.First(); it; it = par.Next()){
        if (0 == strcmp(it->Name(), "dst")){
            Parser::Value parValue1(it->Value());
            for (const char* value1 = parValue1.First(); value1; value1 = parValue1.Next()){
                VImageData vimagedata;
                Parser::Value parValue2(value1);
                for (const char* value2 = parValue2.First(); value2; value2 = parValue2.Next()){
                    ImageData* imagedata = this->GetDestImageData(value2);
                    if (imagedata) vimagedata.push_back(imagedata);
                }
                if (vimagedata.size() > 0){
                    destimagedata.push_back(vimagedata);
                }
            }
        } else if (0 == strcmp(it->Name(), "image")){
            imagevalue = it->Value();
        }
    }

    size_t size = destimagedata.size();
    size_t i = 0;
    Parser::Value parValue(imagevalue.GetString());
    for (const char* value = parValue.First(); value; value = parValue.Next()){
        if (i >= size) break;

        VImageData vimagedata = destimagedata.at(i);
        ImageData imgdata;

        Parser par(value);
        for (Parser::Attribute* it = par.First(); it; it = par.Next()){
            const char* name = it->Name();
            if (0 == strcmp(name, "img")){
                imgdata.Reset(it->Value(), 0, 0, 0, 0, 0);
                TextureMgr* textureMgr = m_wnd->GetTextureMgr();
                if (!textureMgr->Get(it->Value())){
                    IEnginePtr->LoadTexture(m_wnd, it->Value());
                }
            } else if (0 == strcmp(name, "id")){
                int id = -1;
                if (ParserInt(it->Value(), &id, -1) && (id >= 0)){
                    SurfaceMgr* surfaceMgr = IEnginePtr->GetSurfaceMgr();
                    ISurface* surface = surfaceMgr->Get(id);
                    if (!surface) return;
                    const char* keyname = surfaceMgr->GetName(surface);
                    if (!keyname) return;

                    TextureMgr* textureMgr = m_wnd->GetTextureMgr();
                    if (!textureMgr->Get(keyname)){
                        IEnginePtr->LoadTexture(m_wnd, id);
                    }
                    imgdata.Reset(keyname, 0, 0, 0, 0, 0);
                }
            } else if (0 == strcmp(name, "mask")){
                imgdata.Reset(0, 0, 0, 0, 0, 0, it->Value());
                IEnginePtr->LoadSurface(it->Value());
            } else if (0 == strcmp(name, "maskid")){
                int id = -1;
                if (ParserInt(it->Value(), &id, -1) && (id >= 0)){
                    SurfaceMgr* surfaceMgr = IEnginePtr->GetSurfaceMgr();
                    ISurface* surface = surfaceMgr->Get(id);
                    if (!surface) return;
                    const char* keyname = surfaceMgr->GetName(surface);
                    if (!keyname) return;

                    imgdata.Reset(0, 0, 0, 0, 0, 0, keyname);
                }
            } else if (0 == strcmp(name, "src")){
                Rect rc = ParserRect(it->Value());
                imgdata.Reset(0, &rc, 0, 0, 0, 0);
            } else if (0 == strcmp(name, "drc")){
                Rect rc = ParserRect(it->Value());
                imgdata.Reset(0, 0, &rc, 0, 0, 0);
            } else if (0 == strcmp(name, "cor")){
                Rect1 rc = ParserRect1(it->Value());
                imgdata.Reset(0, 0, 0, &rc, 0, 0);
            } else if (0 == strcmp(name, "hole")){
                bool b = ParserBool(it->Value());
                imgdata.Reset(0, 0, 0, 0, &b, 0);
            } else if (0 == strcmp(name, "center")){
                bool b = ParserBool(it->Value());
                imgdata.Reset(0, 0, 0, 0, 0, &b);
            }
        }

        for (VImageData::iterator it = vimagedata.begin(); it != vimagedata.end(); ++it){
            if(*it){
                (*it)->Reset(&imgdata);
            }
        }

        ++i;
    }

    this->Invaldate();
}

void _SetStatusImage(VImageData& vimagedata, ImageData& imgdata, Rect& rc)
{
    imgdata.Reset(0, &rc, 0, 0, 0, 0);

    for (VImageData::iterator it = vimagedata.begin(); it != vimagedata.end(); ++it){
        if(*it){
            (*it)->Reset(&imgdata);
        }
    }
}

void _SetStatusImage(DestImageData& destimagedata, ImageData& imagedata, Size &size, int& num, int width, bool v)
{
    int bx = 0;
    int by = 0;
    int ex = 0;
    int ey = 0;

    if (imagedata.src){
        bx = imagedata.src->x;
        by = imagedata.src->y;
        ex = imagedata.src->x + imagedata.src->w;
        ey = imagedata.src->y + imagedata.src->h;
    }

    Rect rc;

    if (v){
        for (int i = 0; i < width; ++i){
            for (int j = 0; (i * width + j) < num; ++j){
                rc.Reset(bx + i * size.w, by + j * size.h, size.w, size.h);
                
                if (ex && (rc.x + rc.w > ex)) continue;
                if (ey && (rc.y + rc.h > ey)) continue;
                
                VImageData vimagedata = destimagedata.at(i * width + j);
                _SetStatusImage(vimagedata, imagedata, rc);
            }

        }
    } else {
        for (int i = 0; i < width; ++i){
            for (int j = 0; (i * width + j) < num; ++j){
                rc.Reset(bx + j * size.w, by + i * size.h, size.w, size.h);
                
                if (ex && (rc.x + rc.w > ex)) continue;
                if (ey && (rc.y + rc.h > ey)) continue;
                
                VImageData vimagedata = destimagedata.at(i * width + j);
                _SetStatusImage(vimagedata, imagedata, rc);
            }

        }
    }
}

typedef std::vector<DestImageData> VDestImageData;

void Control::SetStatusImage(const char* statusimagestr)
{
    if (!statusimagestr) return;

    VDestImageData vdestimagedata;
    String imagevalue;

    Parser par(statusimagestr);
    for (Parser::Attribute* it = par.First(); it; it = par.Next()){
        if (0 == strcmp(it->Name(), "dst")){
            Parser::Value parValue1(it->Value());
            for (const char* value1 = parValue1.First(); value1; value1 = parValue1.Next()){
                DestImageData destimagedata;
                Parser::Value parValue2(value1);
                for (const char* value2 = parValue2.First(); value2; value2 = parValue2.Next()){
                    VImageData vimagedata;
                    Parser::Value parValue3(value2);
                    for (const char* value3 = parValue3.First(); value3; value3 = parValue3.Next()){
                        ImageData* imagedata = this->GetDestImageData(value3);
                        if (imagedata) vimagedata.push_back(imagedata);
                    }
                    if (vimagedata.size() > 0){
                        destimagedata.push_back(vimagedata);
                    }
                }
                if (destimagedata.size() > 0){
                    vdestimagedata.push_back(destimagedata);
                }
            }
        } else if (0 == strcmp(it->Name(), "status")){
            imagevalue = it->Value();
        }
    }

    size_t size = vdestimagedata.size();
    size_t i = 0;
    Parser::Value parValue(imagevalue.GetString());
    for (const char* value = parValue.First(); value; value = parValue.Next()){
        if (i >= size) break;

        DestImageData destimagedata = vdestimagedata.at(i);
        ImageData imgdata;
        Size size;
        int num = 0;
        bool v = true;
        int width = 0;

        Parser par(value);
        for (Parser::Attribute* it = par.First(); it; it = par.Next()){
            const char* name = it->Name();
            if (0 == strcmp(name, "img")){
                imgdata.Reset(it->Value(), 0, 0, 0, 0, 0);
                TextureMgr* textureMgr = m_wnd->GetTextureMgr();
                if (!textureMgr->Get(it->Value())){
                    IEnginePtr->LoadTexture(m_wnd, it->Value());
                }
            } else if (0 == strcmp(name, "id")){
                int id = -1;
                if (ParserInt(it->Value(), &id, -1) && (id >= 0)){
                    SurfaceMgr* surfaceMgr = IEnginePtr->GetSurfaceMgr();
                    ISurface* surface = surfaceMgr->Get(id);
                    if (!surface) return;
                    const char* keyname = surfaceMgr->GetName(surface);
                    if (!keyname) return;

                    TextureMgr* textureMgr = m_wnd->GetTextureMgr();
                    if (!textureMgr->Get(keyname)){
                        IEnginePtr->LoadTexture(m_wnd, id);
                    }
                    imgdata.Reset(keyname, 0, 0, 0, 0, 0);
                }
            } else if (0 == strcmp(name, "mask")){
                imgdata.Reset(0, 0, 0, 0, 0, 0, it->Value());
                IEnginePtr->LoadSurface(it->Value());
            } else if (0 == strcmp(name, "maskid")){
                int id = -1;
                if (ParserInt(it->Value(), &id, -1) && (id >= 0)){
                    SurfaceMgr* surfaceMgr = IEnginePtr->GetSurfaceMgr();
                    ISurface* surface = surfaceMgr->Get(id);
                    if (!surface) return;
                    const char* keyname = surfaceMgr->GetName(surface);
                    if (!keyname) return;

                    imgdata.Reset(0, 0, 0, 0, 0, 0, keyname);
                }
            } else if (0 == strcmp(name, "src")){
                Rect rc = ParserRect(it->Value());
                imgdata.Reset(0, &rc, 0, 0, 0, 0);
            } else if (0 == strcmp(name, "drc")){
                Rect rc = ParserRect(it->Value());
                imgdata.Reset(0, 0, &rc, 0, 0, 0);
            } else if (0 == strcmp(name, "cor")){
                Rect1 rc = ParserRect1(it->Value());
                imgdata.Reset(0, 0, 0, &rc, 0, 0);
            } else if (0 == strcmp(name, "hole")){
                bool b = ParserBool(it->Value());
                imgdata.Reset(0, 0, 0, 0, &b, 0);
            } else if (0 == strcmp(name, "center")){
                bool b = ParserBool(it->Value());
                imgdata.Reset(0, 0, 0, 0, 0, &b);
            } else if (0 == strcmp(name, "size")){
                size = ParserSize(it->Value());
            } else if (0 == strcmp(name, "num")){
                ParserInt(it->Value(), &num, 0);
            } else if (0 == strcmp(name, "type")){
                const char* tmp = it->Value();
                if ('v' == tmp[0]) v = true;
                else v = false;
                ParserInt((tmp + 1), &width, 0);
            }
        }

        if (width == 0){
            Log("[EDUI] %s SetStatusImage error : status is (%s).", this->GetName(), value);
            continue;
        }

        _SetStatusImage(destimagedata, imgdata, size, num, width, v);

        ++i;
    }

    this->Invaldate();
}

IWindow* Control::GetWindow() const
{
    return m_wnd;
}

bool Control::SetWindow(IWindow* wnd)
{
    if (!wnd || !wnd->IsOK()) return false;
    m_wnd = wnd;
    return true;
}

bool Control::SetParent(Control* ctrl)
{
    if (!ctrl || !ctrl->IsOK()) return false;
    m_parent = ctrl;
    return true;
}

Control* Control::GetParent() const
{
    return m_parent;
}

void Control::DoEvent(EventType type, void* data1, void* data2)
{}

bool Control::NeedRender(const Rect* rc)
{
    if (!rc) return true;
    return m_rc.IsUnion(rc);
}

void Control::Invaldate(const Rect* rc)
{
    if (!rc) rc = &m_rc;
    if (!m_rc.IsUnion(rc)) return;

    Container* parent = Container::ToContainer(this->GetParent());
    if (parent && !parent->ChildCanInvaldate(this)) return;
    
    m_wnd->Invaldate(rc);
}

bool Control::LoadLayout(const char* xmlstr)
{
    if (!xmlstr || !this->IsOK()) return false;
    TiXmlElement xml(xmlstr);
    return this->LoadLayout(xml.FirstChildElement());
}

bool Control::LoadLayout(TiXmlElement* root)
{
    if (!root || !this->IsOK()) return false;
    for (TiXmlAttribute* attr = root->FirstAttribute(); attr; attr = attr->Next()){
        this->SetAttribute(attr->Name(), attr->Value());
    }
    this->AfterSetAttribute();
    return true;
}

Rect Control::GetImageDrawRect(const Rect* imgRc, const Rect1* rcInset)
{
    Rect rc = m_rc;
    if (m_rcFixed.w) rc.w = m_rcFixed.w;
    if (m_rcFixed.h) rc.h = m_rcFixed.h;
    if (imgRc){
        rc.x += imgRc->x;
        rc.y += imgRc->y;
        rc.w = imgRc->w;
        rc.h = imgRc->h;
    }
    if (rcInset){
        rc.x += rcInset->l;
        rc.y += rcInset->t;
        rc.w -= (rcInset->l + rcInset->r);
        rc.h -= (rcInset->t + rcInset->b);
    }
    return rc;
}

void Control::RenderBkColor(IRender* render, const Rect* rc)
{
    render->SetColor(&m_bkColor);
    render->FillRect(&m_rc);
}

void Control::DrawImage(IRender* render, ImageData* image, const Rect1* rcInset)
{
    if (!render || !image || image->img.IsEmpty()) return;

    ISurface* mask = 0, *img = 0;
    ITexture* texture = 0;
    if (!image->mask.IsEmpty()){
        SurfaceMgr* surfaceMgr = IEnginePtr->GetSurfaceMgr();
        mask = surfaceMgr->Get(image->mask.GetString());
        if (!mask || !mask->IsOK()) return;
    }

    if (!mask){ 
        TextureMgr* textureMgr = m_wnd->GetTextureMgr();
        texture = textureMgr->Get(image->img.GetString());
        if (!texture || !texture->IsOK()) return;
    } else {
        SurfaceMgr* surfaceMgr = IEnginePtr->GetSurfaceMgr();
        img = surfaceMgr->Get(image->img.GetString());
        if (!img || !img->IsOK()) return;
    }

    Rect rc = this->GetImageDrawRect(image->dst, rcInset);
    if (image->center){
        Size sz;
        if (mask) sz = img->GetSize();
        else sz = texture->GetSize();
        if (image->src){
            sz.w = image->src->w;
            sz.h = image->src->h;
        }
        rc.Reset((rc.w - sz.w) / 2 + rc.x, (rc.h - sz.h) / 2 + rc.y, sz.w, sz.h);
    }

    if (mask) render->DrawMaskTexture(img, mask, image->src, &rc);
    else if(image->cor) render->DrawScaleTexture(texture, image->src, &rc, image->cor, image->hole);
    else render->DrawTexture(texture, image->src, &rc);
}

void Control::DrawImage(IRender* render, ImageData* image, const Rect* rcs)
{
    if (!render || !image || !rcs || image->img.IsEmpty()) return;

    ISurface* mask = 0, *img = 0;
    ITexture* texture = 0;
    if (!image->mask.IsEmpty()){
        SurfaceMgr* surfaceMgr = IEnginePtr->GetSurfaceMgr();
        mask = surfaceMgr->Get(image->mask.GetString());
        if (!mask || !mask->IsOK()) return;
    }

    if (!mask){ 
        TextureMgr* textureMgr = m_wnd->GetTextureMgr();
        texture = textureMgr->Get(image->img.GetString());
        if (!texture || !texture->IsOK()) return;
    } else {
        SurfaceMgr* surfaceMgr = IEnginePtr->GetSurfaceMgr();
        img = surfaceMgr->Get(image->img.GetString());
        if (!img || !img->IsOK()) return;
    }

    Rect rc = *rcs;
    if (image->center){
        Size sz;
        if (mask) sz = img->GetSize();
        else sz = texture->GetSize();
        if (image->src){
            sz.w = image->src->w;
            sz.h = image->src->h;
        }
        rc.Reset((rc.w - sz.w) / 2 + rc.x, (rc.h - sz.h) / 2 + rc.y, sz.w, sz.h);
    }
    
    if (mask) render->DrawMaskTexture(img, mask, image->src, &rc);
    else if(image->cor) render->DrawScaleTexture(texture, image->src, &rc, image->cor, image->hole);
    else render->DrawTexture(texture, image->src, &rc);
}

void Control::RenderBkImages(IRender* render, const Rect* rc)
{
    this->DrawImage(render, &m_bkImage);
    if (m_ainmation){
        AnimationFrame *frame = m_ainmation->GetCurFrame();
        if (frame){
            Rect rc = m_rc;
            rc.x += frame->x;
            rc.y += frame->y;
            rc.w = frame->w;
            rc.h = frame->h;
            render->DrawTexture(frame->texture, 0, &rc, frame->id);
        }
    }
}

void Control::RenderStatusImages(IRender* render, const Rect* rc)
{}

void Control::RenderForeImages(IRender* render, const Rect* rc)
{
    this->DrawImage(render, &m_foreImage);
}

void Control::RenderText(IRender* render, const Rect* rc)
{}

void Control::RenderBorder(IRender* render, const Rect* rc)
{}

void Control::Render(IRender* render, const Rect* rc)
{
    Rect oldclip = render->GetClip();

    if (rc) render->SetClip(rc);
    else render->SetClip(&m_rc);

    this->RenderBkColor(render, rc);
    this->RenderBkImages(render, rc);
    this->RenderStatusImages(render, rc);
    this->RenderForeImages(render, rc);
    this->RenderText(render, rc);
    this->RenderBorder(render, rc);

    render->SetClip(&oldclip);
}

Control* Control::FindControl(const char* name)
{
    if (0 == strcmp(name, m_name.GetString())) return this;
    return 0;
}

Control* Control::FindControlByTabID(int id)
{
    if (id == m_tabID) return this;
    return 0;
}

Control* Control::FindControlByPt(int x, int y, Uint32 flag)
{
    if (!this->IsInRect(x, y)) return 0;
    if (flag == FIND_ALL){
        return this;
    } else if (flag & FIND_NOVISIBLE){
        if (m_bVisible) return this;
    } else if (flag & FIND_NODISABLED){
        if (m_bEnabled) return this;
    }
    return 0;
}

Control* Control::FindParent(const char* name)
{
    if (0 == strcmp(name, m_name.GetString())) return this;
    if (!m_parent) return 0;
    return m_parent->FindParent(name);
}

void Control::SetTabID(int id)
{
    m_tabID = id;
}

int Control::GetTabID() const
{
    return m_tabID;
}

void Control::SetAnimation(Animation* animation, bool start)
{
    if (m_ainmation == animation) return;
    if (animation){
        animation->AddNotify(this);
        if (start && !animation->IsRun()) animation->Start();
    } else {
        if (m_ainmation) m_ainmation->RemoveNotify(this);
    }
    m_ainmation = animation;
}

Animation* Control::GetAnimation()
{
    return m_ainmation;
}

bool Control::HandleMsg(Msg* msg)
{
    if (!m_bFloat) return false;
    if ((msg->msg >= MSG_MOUSE_MOVE) && (msg->msg <= MSG_MOUSE_WHEEL)){
        MouseMoveMsg* evt = &msg->motion;
        if (this->IsInRect(evt->x, evt->y)){
            return true;
        }
    }
    return false;
}

void Control::AutoLayout()
{
    Rect rc = m_rc;
    if (m_bFloat){
        m_rc.x += m_rcFixed.x;
        m_rc.y += m_rcFixed.y;
    } else {
        m_rc.x += m_rcPadding.l;
        m_rc.y += m_rcPadding.t;
        m_rc.w -= (m_rcPadding.l + m_rcPadding.r);
        m_rc.h -= (m_rcPadding.t + m_rcPadding.b);
        rc = m_rc;
    }

    Size sz = this->GetFixedSize();

    m_rc.w = sz.w == 0 ? m_rc.w : EDUI_MIN(m_rc.w, sz.w);
    m_rc.h = sz.h == 0 ? m_rc.h : EDUI_MIN(m_rc.h, sz.h);

    if (m_rc.x + m_rc.w > rc.x + rc.w) m_rc.w = rc.x + rc.w - m_rc.x;
    if (m_rc.y + m_rc.h > rc.y + rc.h) m_rc.h = rc.y + rc.h - m_rc.y;
}

void Control::SetAttribute(const char* name, const char* value)
{
    if (0 == strcmp(name, "name")){
        this->SetName(value);
    } else if (0 == strcmp(name, "width")){
        int i = 0;
        if (ParserInt(value, &i)){
            m_rcFixed.w = i;
        }
    } else if (0 == strcmp(name, "height")){
        int i = 0;
        if (ParserInt(value, &i)){
            m_rcFixed.h = i;
        }
    } else if (0 == strcmp(name, "pos")){
        Point pt = ParserPoint(value);
        this->SetFixedPos(&pt);
    } else if (0 == strcmp(name, "size")){
        Size sz = ParserSize(value);
        this->SetFixedSize(&sz);
    } else if (0 == strcmp(name, "padding")){
        Rect1 rc = ParserRect1(value);
        this->SetPadding(&rc);
    } else if (0 == strcmp(name, "float")){
        bool b = ParserBool(value, true);
        this->SetFloat(b);
    } else if (0 == strcmp(name, "visible")){
        bool b = ParserBool(value, true);
        this->SetVisible(b);
    } else if (0 == strcmp(name, "enabled")){
        bool b = ParserBool(value, true);
        this->SetEnabled(b);
    } else if (0 == strcmp(name, "mouseenabled")){
        bool b = ParserBool(value, true);
        this->SetMouseEnabled(b);
    } else if (0 == strcmp(name, "keyboardenabled")){
        bool b = ParserBool(value, true);
        this->SetKeyboardEnabled(b);
    } else if (0 == strcmp(name, "dragwindow")){
        bool b = ParserBool(value, false);
        m_bDragWnd = b;
    } else if (0 == strcmp(name, "color")){
        this->SetColor(value);
    } else if (0 == strcmp(name, "image")){
        this->SetImage(value);
    } else if (0 == strcmp(name, "statusimage")){
        this->SetStatusImage(value);
    } else if (0 == strcmp(name, "cursor")){
        CursorMgr* mgr = IEnginePtr->GetCursorMgr();
        ICursor* cursor = mgr->Get(value);
        this->SetCursor(cursor);
    } else if (0 == strcmp(name, "cursorid")){
        int i = 0;
        if (ParserInt(value, &i)){
            CursorMgr* mgr = IEnginePtr->GetCursorMgr();
            ICursor* cursor = mgr->Get(i);
            this->SetCursor(cursor);
        }
    } else if (0 == strcmp(name, "tabid")){
        int i = 0;
        if (ParserInt(value, &i)){
            this->SetTabID(i);
        }
    } else if (0 == strcmp(name, "animation")){
        this->SetAnimation(m_wnd->FindAnimation(value));
    } else if (0 == strcmp(name, "animationid")){
        int i = 0;
        if (ParserInt(value, &i)){
            this->SetAnimation(m_wnd->FindAnimation(i));
        }
    }
}

void Control::AfterSetAttribute()
{}

void Control::OnFocus()
{}

void Control::OnKillFocus()
{}

void Control::OnMouseIn()
{
    if (m_cursor){
        IEnginePtr->SetCursor(m_cursor);
    }
}

void Control::OnMouseOut()
{
    if (m_cursor){
        IEnginePtr->SetCursor(m_wnd->GetCursor());
    }
}
//-------------------------------//

ImageData::ImageData()
{
    img.Empty();
    mask.Empty();
    src = 0;
    dst = 0;
    cor = 0;
    hole = false;
    center = false;
}

ImageData::~ImageData()
{
    if (src){
        delete src;
        src = 0;
    }
    if (dst){
        delete dst;
        dst = 0;
    }
    if (cor){
        delete cor;
        cor = 0;
    }
    img.Empty();
    mask.Empty();
    hole = false;
    center = false;
}

void ImageData::Reset(const char* _img, Rect* _src, Rect* _dst, Rect1* _cor, bool* _hole, bool* _center, const char* _mask)
{
    if (_img){
        img = _img;
    }
    if (_src){
        if (!src) src = new Rect();
        *src = *_src;
    }
    if (_dst){
        if (!dst) dst = new Rect();
        *dst = *_dst;
    }
    if (_cor){
        if (!cor) cor = new Rect1();
        *cor = *_cor;
    }
    if (_hole){
        hole = *_hole;
    }
    if (_center){
        center = *_center;
    }
    if (_mask){
        mask = _mask;
    }
}

void ImageData::Reset(ImageData* imgdata)
{
    this->Reset(imgdata->img.GetString(), imgdata->src, imgdata->dst, imgdata->cor, &imgdata->hole, &imgdata->center, imgdata->mask.GetString());
}

EDUI_NAMESPACE_END
